﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Security;
using Argotic.Syndication;
using Argotic.Extensions.Core;
using Castle.Core;
using Castle.MonoRail.Framework;
using Castle.MonoRail.Framework.Filters;
using Castle.MonoRail.Framework.Helpers;
using StateTheater.Models;
using StateTheaterDataModel;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Configuration;
using anrControls;
using Castle.Windsor;

namespace StateTheater.Controllers
{
	[Layout("default"), Rescue("generalerror")]
	[Filter(ExecuteWhen.BeforeAction, typeof(MobileFilter))]
	public class ShowController : SmartDispatcherController
	{
		public IWindsorContainer Container { get; set; }

		public StateTheaterDataContext db { get; set; }
		public ShowController()
		{
		}

		public ShowController(StateTheaterDataContext db)
		{
			this.db = db;
		}
		public void PlayingWhen(DateTime when)
		{
			if (when == DateTime.MinValue)
				when = DateTime.Now;

			PropertyBag["announcement"] =
						(from annn in db.Announcements
								where (annn.StartDate == null || annn.StartDate < DateTime.Now)
								&& (annn.EndDate == null || annn.EndDate > DateTime.Now)
								orderby annn.Priority descending
								select annn.Text).FirstOrDefault() ?? String.Empty;

			var q = from prod in db.Productions
					where prod.FirstPerformance < when.AddDays(8)
					&& prod.LastPerformance > when.AddDays(-1)
					&& prod.FlowerID == null
					orderby prod.Play.SortTitle
					select new ShowListing
					{
						Title = prod.Play.Title,
						PlayId = prod.PlayID,
						Description = prod.Play.Comments,
						ProductionId = prod.ProductionID,
						Troupe = prod.Troupe.Name,
						TroupeShortName = prod.Troupe.shortname,
						TroupeId = prod.TroupeID,
						Venue = prod.Venue.Name,
						VenueShortName = prod.Venue.Shortname,
						VenueId = prod.VenueID.Value,
						City = prod.Venue.City,
						FirstPerformance = prod.FirstPerformance,
						LastPerformance = prod.LastPerformance.Value,
						AnthologyFlag = prod.AnthologyFlag,
						OpeningDateClass = "Date",
						ClosingDateClass = "Date"
					};

			List<ShowListing> shows = q.ToList();
			TimeSpan oneWeek = new TimeSpan(7, 0, 0, 0);
			foreach (ShowListing show in shows)
			{
				show.Troupe = Util.AdjTitle(show.Troupe);
				show.Venue = Util.AdjTitle(show.Venue);
				TimeSpan diff = (show.FirstPerformance - DateTime.Now).Duration();
				if (diff < oneWeek)
				{
					show.OpeningDateClass = "ThisWeek";
				}
				diff = (show.LastPerformance - DateTime.Now).Duration();
				if (diff < oneWeek)
				{
					show.ClosingDateClass= "ThisWeek";
				}

//				show.Organizations = string.Join(" ", db.Associations.Where(tr => tr.TroupeID == show.TroupeId).Select(a => a.Organization.Trim()).ToArray());
				show.Organizations = db.Associations.Where(tr => tr.TroupeID == show.TroupeId).ToArray().BuildList(" ", a => a.Organization.Trim());
//				var  authors = db.PlayCredits.Where(pc => pc.PlayID == show.PlayId).Distinct().ToList();
				var authors = (from pc in db.PlayCredits where pc.PlayID == show.PlayId orderby pc.CreditID select pc.People.FullName).Distinct().ToList();
				show.Authors = authors.Count == 0 ? "" : "(" + authors.BuildList(",") + ")&nbsp;";
			}
			PropertyBag["Shows"] = shows;
			PropertyBag["date"] = when;
			LayoutNames = new string[] { "default", "front" };
			RenderView("playing");
		}
		public void Playing()
		{
			PlayingWhen(DateTime.Now);

		}

		public void Planning()
		{
			Planning(DateTime.Today);
		}

		public void Planning(DateTime when)
		{
			if (when == DateTime.MinValue)
				when = DateTime.Today;

			var rawperfs = (from p in db.Performances
						   where p.date > when.AddHours(-2) && p.date < when.AddDays(8)
						 orderby p.date
						 select new
						 {
							 PerfDate = p.date,
							 TroupeName = p.Production.Troupe.Name,
							 TroupeShortName = p.Production.Troupe.shortname,
							 TroupeId = p.Production.TroupeID,
							 VenueName = p.Production.Venue.Name,
							 VenueId = p.Production.VenueID,
							 Title = p.Production.Play.Title,
							 PK = p.PK,
							 ProductionId = p.ProductionID,
							 PlayId = p.Production.PlayID,
							 AnthologyFlag = p.Production.AnthologyFlag
						 }).ToList();

			var perfs = (from pp in rawperfs
						 group pp by pp.PerfDate.Value.Date into g
						 select new { Date = g.Key, Shows = g.ToList() });

			PropertyBag["Perfs"] = perfs;
/*
 * SELECT     Performances_1.date AS PREF_DATE, Troupes_1.Name AS TROUPE_NAME, Troupes_1.TroupeID, Venues_1.Name AS VENUE_NAME, 
					  Venues_1.VenueID, Plays_1.Title, PK, Productions_1.ProductionID, Plays_1.PlayID, Productions_1.AnthologyFlag
FROM         Venues Venues_1 INNER JOIN
					  Troupes Troupes_1 INNER JOIN
					  Plays Plays_1 INNER JOIN
					  Productions Productions_1 ON Plays_1.PlayID = Productions_1.PlayID INNER JOIN
					  Performances Performances_1 ON Productions_1.ProductionID = Performances_1.ProductionID ON 
					  Troupes_1.TroupeID = Productions_1.TroupeID ON Venues_1.VenueID = Productions_1.VenueID
WHERE     (Performances_1.date > DATEADD(hour, - 2, @SEEK_Date)) AND (Performances_1.date < DATEADD(day, 8, @SEEK_Date))
ORDER BY Performances_1.date

 */

			var noperfs = (from p in db.Productions
						   where p.LastPerformance > when.AddHours(-2) && p.FirstPerformance < when.AddDays(8)
							   && !p.Performances.Any()
						   select new
													{
														TroupeName =Util.AdjTitle(p.Troupe.Name),
														TroupeShortName = p.Troupe.shortname,
														TroupeId = p.TroupeID,
														VenueName = p.Venue.Name,
														VenueId = p.VenueID,
														City = p.Venue.City,
														Title = p.Play.Title,
														ProductionId = p.ProductionID,
														PlayId = p.PlayID,
														AnthologyFlag = p.AnthologyFlag,
														p.FirstPerformance,
														p.LastPerformance,
														Closing = p.LastPerformance < when.AddDays(8),
														Opening = p.FirstPerformance > when
													}).ToList();
			PropertyBag["noperfs"] = noperfs;
			PropertyBag["date"] = when;
			PropertyBag["action"] = "planning";

			this.LayoutNames = new string[] { "default", "front" };
		}

		public void Display(int id)
		{
			/*
			 * CREATE PROCEDURE [NewNJT_Admin  ].[Production_details](@ID integer)
AS SELECT     T.Name AS TROUPE_NAME, PL.Title, PL.Comments AS PLAY_DESC, PL.PlayID, PL.rights, PL.StagePlaysID, V.Name AS VENUE_NAME, 
					  PR.Comments AS PROD_DESC, PR.ProductionID, PR.VenueID + 0 AS VenueID, PR.TroupeID, PR.FlowerID, PR.Comments, PR.FirstPerformance, 
					  PR.LastPerformance, PR.HasPerfs, PR.HasCast, PR.HasPhotos
FROM         Venues V INNER JOIN
					  Troupes T INNER JOIN
					  Plays PL INNER JOIN
					  Productions PR ON PL.PlayID = PR.PlayID ON T.TroupeID = PR.TroupeID ON V.VenueID = PR.VenueID
WHERE     (PR.ProductionID = @ID)
			 */
			var prod = (from pr in db.Productions
					where pr.ProductionID == id
					select new 
						   {
							   Production = pr,
							   TroupeName = pr.Troupe.Name,
							   Title = pr.Play.Title,
							   PlayDesc = pr.Play.Comments,
							   Rights = pr.Play.Rights,
							   StatePlaysID = pr.Play.StagePlaysID,
							   VenueName = pr.Venue.Name,
							   TroupeShortName = pr.Troupe.shortname,
						   }).FirstOrDefault();

			PropertyBag["Production"] = prod.Production;
			PropertyBag["TroupeName"] = Util.AdjTitle(prod.TroupeName);
			PropertyBag["Title"] = Util.AdjTitle(prod.Title);
			PropertyBag["PlayDesc"] = prod.PlayDesc;
			PropertyBag["Comments"] = prod.Production.Comments;
			PropertyBag["Rights"] = prod.Rights;
			PropertyBag["StatePlaysID"] = prod.StatePlaysID;
			PropertyBag["VenueName"] = Util.AdjTitle(prod.VenueName);
			PropertyBag["TroupeShortName"] = prod.TroupeShortName;

			// This section really should be moved into the view.
			PropertyBag["PerformanceMessage"] = "are running";
			if (!prod.Production.LastPerformance.HasValue)
			{
				PropertyBag["PerformanceMessage"] = "began";
			}
			else if (prod.Production.FirstPerformance > DateTime.Now)
			{
				PropertyBag["PerformanceMessage"] = "run";
			}
			else if (prod.Production.LastPerformance < DateTime.Now)
			{
				PropertyBag["PerformanceMessage"] = "ran";
			}

			PropertyBag["Authors"] = PlayController.GetAuthors(this.Context, prod.Production.PlayID);


			var reviews = (from r in db.Reviews
									  where r.ProductionID == id
									  select new myReview { URL = r.URL, Source = "Other" }).ToList();
			foreach (var r in reviews)
			{
				if (r.URL.IndexOf("njtheater.com")> 0) r.Source="NJTheater.com Forums";
				if (r.URL.IndexOf("zwire.com") > 0) r.Source="Princeton Packet";
				if (r.URL.IndexOf("/features/times") > 0) r.Source = "Trenton Times";
			}

			PropertyBag["Reviews"] = reviews;
			PropertyBag["ReviewsCnt"] = reviews.Count;

			PropertyBag["Products"] = db.Products.Where(p => p.PlayID == prod.Production.PlayID).Select(p => new Pair<string, string>(p.Vendor, p.Code));


		}

		class myReview
		{
			public string URL  {get; set;}
			public string Source { get; set; }
		}


		public void Cast(int[] ID)
		{
			Cast(ID[0]);
		}

		public void Cast(int ID)
		{
			RoleAward raNULL = new RoleAward() { AwardID = Int32.MaxValue, Year = 0, Win = false };
			
			// This ridiculous set of queries implements the incredibly baroque method in which cast members
			// are listed, namely:
			// Award winners first (in order of "importance" of award)
			// Losing award nominees (in order of "importance" of award)
			// then other cast, ordered first by number of people playing that role (fewer first) 
			// then alphabetical by role name, so that "Scrooge" comes before "Tiny Tim", but both 
			// come before the five in the "Chorus" and the ten in the "Ensemble".
			var L1 = (from r1 in db.Roles
					  where r1.ProductionID == ID
					  select new CastItem
					  {
						  Person = new NameDetails
						  {
							  FirstName = r1.People.FirstName,
							  LastName = r1.People.LastName,
//                              FullName = r1.People.FullName,
							  HasPhoto = r1.People.Photo == null ? false : r1.People.Photo.Length > 0,
							  HasBio = r1.People.Bio == null ? false : r1.People.Bio.Length > 0,
							  ID = r1.PersonID,
						  },
						  Role = r1.Role1,
						  RoleID = r1.RoleID,
						  Award = raNULL // (RoleAward)null
					  }).ToList();
			L1.ForEach(c => c.Person.SEOName = Util.SEOEscape(c.Person.FullName, true));

			var q2 = (from r2 in db.Roles
					  where r2.ProductionID == ID
					  group r2 by r2.Role1
						).Select(r3 => new { Role = r3.Key, Count = r3.Count() }); ;

			var L3 = (from r4 in db.RoleAwards
					  where r4.Role.ProductionID == ID
					  select r4).ToLookup(i => i.RoleID);


			if (L3.Any())
				L1.ForEach(l1 => l1.Award = (L3[l1.RoleID].FirstOrDefault() ?? raNULL));

			var Castlist = L1.Join(q2,
							   l => l.Role,
							   r => r.Role,
							   (l, r) => new { l.Person, l.Role, l.Award, r.Count })
				.OrderByDescending(r => r.Award.Win)
				.ThenBy(r => r.Award.AwardID)
				.ThenBy(r => r.Count)
				.ThenBy(r => r.Role)
				.ThenBy(r => r.Person.LastName)
				.ToList();

			PropertyBag["cast"] = Castlist;


			// Ordering the crew list is much easier.  They are just listed
			// in the order of the of their "importance" (ie, credit id)

			var CrewList = (from crew in db.ProductionCredits
						   where crew.ProductionID == ID
						   orderby crew.CreditName.CreditID, crew.People.LastName
						   select new
						   {
							   Person = new NameDetails
							   {
								   FirstName = crew.People.FirstName,
								   LastName = crew.People.LastName,
//                                   FullName = crew.People.FullName,
								   ID = crew.People.PersonID,
								   HasPhoto = crew.People.Photo == null ? false : crew.People.Photo.Length > 0,
								   HasBio = crew.People.Bio == null ? false : crew.People.Bio.Length > 0,
							   },
							   crew.CreditName.Credit,
						   }).ToList();
			CrewList.ForEach(c => c.Person.SEOName = Util.SEOEscape(c.Person.FullName, true));
			PropertyBag["Crew"] = CrewList;
			PropertyBag["details"] = ProductionDetails.GetDetails(db, ID);
		}

		public void CastMediaRss(int id)
		{
			PropertyBag["details"] = (from c in db.Roles
									  where c.ProductionID == id && c.People.Photo != null
									  select new
									  {
										  c.People.FullName,
										  Bio = c.People.Bio,
										  Id = c.People.PersonID,
										  c.People.Photo,
										  SEOName=Util.SEOEscape(c.People.FullName, false)
									  }).ToArray();
			CancelLayout();
			Response.ContentType = "application/rss+xml";
		}

		public void Performances(int id)
		{
			PropertyBag["details"] = ProductionDetails.GetDetails(db, id);

			PropertyBag["perfs"] = (
				from pr in db.Performances
				where pr.ProductionID == id && pr.date != null
				orderby pr.date
				select new Pair<DateTime, int>(pr.date.Value, pr.PK)).ToList();
		}
		
		public void Photos(int id)
		{
			PropertyBag["details"] = ProductionDetails.GetDetails(db, id);

			PropertyBag["photos"] = GetPhotoList(db, id);
		}


		public static PhotoItem[] GetPhotoList(StateTheaterDataContext db, int prodId)
		{
			return (from ph in db.Photos
				where ph.productionID == prodId
				select new PhotoItem
				{
					ID = ph.PK,
					Filename = ph.Filename,
					Caption = ph.Caption
				}).ToArray();
		}

		public static string StillsFolder(Controller ctrl)
		{
			return Path.Combine(ctrl.Context.ApplicationPhysicalPath, @"Content\Images\Stills");
		}
		public void Image(string fn)
		{
			CancelView();
			int height = 0;
			int width = 0;
			int size;
			if (Int32.TryParse(Params["size"], out size))
			{
				height = size;
				width = size;
			}
			else
			{
				Int32.TryParse(Params["height"], out height);
				Int32.TryParse(Params["width"], out width);
			}
			string filename = Path.Combine(StillsFolder(this), fn);

			Bitmap oBitmap = new Bitmap(filename);
			if (height != 0 || width != 0)
			{
				oBitmap = Util.ResizeImage(oBitmap, width, height);
			}
			Response.CachePolicy.SetExpires(DateTime.Today.AddYears(1));
#if (true)
			Response.ContentType = "image/jpg";
			oBitmap.Save(Response.OutputStream, ImageFormat.Jpeg);
#else
			Response.ContentType = "image/png";
			PngBitmapEncoder encoder = new PngBitmapEncoder();
			encoder.Interlace = PngInterlaceOption.On;
			encoder.Frames.Add(BitmapFrame.Create(oBitmap.));
			encoder.Save(Response.OutputStream,);


#endif

		}

		public void vCard(int id)
		{
			var q = (from pr in db.Performances
					 where pr.PK == id
					 select new
					 {
						 pr.date,
						 pr.Production.Play.Title,
						 Troupe = pr.Production.Troupe.Name,
						 Venue = pr.Production.Venue.Name,
						 pr.Production.Venue.Address1,
						 pr.Production.Venue.Address2,
						 pr.Production.Venue.City,
						 pr.Production.Venue.State,
						 pr.Production.Venue.ZipCode,
						 pr.Production.Play.Comments
					 }).First();

			PropertyBag["DSTART"] = q.date.Value.ToUniversalTime().ToString("yyyyMMddTHHmmssZ");
			PropertyBag["DEND"] = q.date.Value.AddHours(2).ToUniversalTime().ToString("yyyyMMddTHHmmssZ");
			PropertyBag["Troupe"] = Util.AdjTitle(q.Troupe);
			PropertyBag["Title"] = Util.AdjTitle(q.Title);
			PropertyBag["Venue"] = Util.AdjTitle(q.Venue);
			PropertyBag["Address1"] = q.Address1;
			PropertyBag["Address2"] = String.IsNullOrEmpty(q.Address2) ? "" : q.Address2 + ",";
			PropertyBag["City"] = q.City;
			PropertyBag["State"] = q.State;
			PropertyBag["ZipCode"] = q.ZipCode;
			PropertyBag["Description"] = String.IsNullOrEmpty(q.Comments) ? "" : q.Comments.Replace('\r', ' ').Replace("\n", "");
			Response.ContentType = "text/calendar";
			CancelLayout();
		}

		public void Headlines()
		{
#if (false)
			var xslt = new XslCompiledTransform();
			var xslpath = Path.Combine(HttpContext.Server.MapPath(@"~/content/css/"), "aeperforming.xsl");
			xslt.Load(xslpath);

			// Execute the transform and output the results to a file.
			xslt.Transform("http://www.prweb.com/rss2/entertainment.xml", null, new ProperyBagTextWriter("feed", PropertyBag));
#endif
			/*
<item>
	<title>Supermodel Carmen Kass Participated in a Gala Dinner Organized for Famous Estonians</title>
	<link>http://www.prweb.com/releases/2009/09/prweb2830434.htm</link>
	<description>
		<![CDATA[  <P>Within the framework of the Estonian Song and Dance Celebration, a merchant originating from Estonia, Margus Reinsalu, and the Estonian Ministry of Foreign Affairs organized a reception to world famous Estonians. Among ca 100 guests, there were such well-known names as a supermodel Carmen Kass, a professional footballer Mart Poom, the President of Estonia Toomas Hendrik Ilves, the biggest investor of Hotmail and Skype Steve J&#252;rvetson, a world-famous architect T&#245;nu Altosaar and many others. (PRWeb Sep 5, 2009)</P>
		<P>Read the full story at <a href="http://www.prweb.com/releases/2009/09/prweb2830434.htm">http://www.prweb.com/releases/2009/09/prweb2830434.htm</a></P>]]>
	</description>
	<guid isPermaLink="true">http://www.prweb.com/releases/2009/09/prweb2830434.htm</guid>
</item>
			 */
			try
			{
#if (false)
			var doc = XElement.Load("http://www.prweb.com/rss2/entertainment.xml");
			var feed = from fd in doc.Elements("channel").Elements("item")
					   select new
					   {
						   Description = XElement.Parse("<x>" + fd.Element("description").Value + "</x>").Elements("P").First().Value,
						   Title = fd.Element("title").Value,
						   Link = fd.Element("link").Value
					   };
			PropertyBag["feed"] = feed.ToList();
#else
				var feed = RssFeed.Create(new Uri("http://www.prweb.com/rss2/entertainment.xml"));
			PropertyBag["feed"] = feed.Channel.Items.ToList();
#endif
			}
			catch(Exception ex)
			{
				PropertyBag["feed"] = new object[1] { new { Title = "An error occurred", Description = ex.Message, Link = ""}};
			}
			CancelLayout();

		}

//------------  Webservices -----------------------------------------------------------------------------------------

		[return:JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public jqFlexboxPacket<ProductionListing> ProductionsJson(string q, int p, int s, bool recentOnly)	// query, page#, pageSize, recentOnly
		{
			var prod1 = (from prod in db.Productions
						 where prod.Play.SortTitle.StartsWith(q) || prod.Play.Title.StartsWith(q)
						 select prod);

			if (recentOnly)
				prod1 = prod1.Where(pr => pr.LastPerformance > DateTime.Now.AddMonths(-3));

			if (! Context.CurrentUser.IsInRole("Admin"))
			{
				MembershipUser user = Membership.GetUser();
				if (user == null || user.ProviderUserKey == null)
				{
					return new jqFlexboxPacket<ProductionListing>();
				}
				int memberId = (int)user.ProviderUserKey;

				var troups = from t in db.TroupePermissions
							 where t.MEMBER_ID == memberId
							 select t.Troupeid;
				prod1.Where(pr => troups.Contains(pr.TroupeID));
			}

			var prods = (from pr in prod1
						 orderby pr.Play.SortTitle, pr.FirstPerformance descending
						 select new ProductionListing
						 {
							 Title = pr.Play.Title,
							 Venue = pr.Venue.Name,
							 Year = pr.FirstPerformance.Year,
							 ID = pr.ProductionID
						 }).Skip(s*p).Take(s).ToList();

			return new jqFlexboxPacket<ProductionListing>(prods.ToArray());
		}

		[return: JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public ProductionListing[] ProductionsJson(string term, int limit, bool recentOnly)
		{
			var prod1 = (from prod in db.Productions
						 where prod.Play.SortTitle.StartsWith(term) || prod.Play.Title.StartsWith(term)
						 select prod);

			if (recentOnly)
				prod1 = prod1.Where(p => p.LastPerformance > DateTime.Now.AddMonths(-3));

			if (! Context.CurrentUser.IsInRole("Admin"))
			{
				MembershipUser user = Membership.GetUser();
				if (user == null || user.ProviderUserKey == null)
				{
					return new ProductionListing[1] { new ProductionListing() { ID = 0, Title = "(not logged in)" } };
				}
				int memberId = (int)user.ProviderUserKey;

				var troups = from t in db.TroupePermissions
							 where t.MEMBER_ID == memberId
							 select t.Troupeid;
				prod1.Where(p => troups.Contains(p.TroupeID));
			}

			var prods = (from p in prod1
						 orderby p.Play.SortTitle, p.FirstPerformance descending
						 select new ProductionListing
						 {
							 Title = p.Play.Title,
							 Venue = p.Venue.Name,
							 Year = p.FirstPerformance.Year,
							 ID = p.ProductionID
						 }).Take(limit).ToArray();
			Response.ContentType = "text/json";
			return prods;
		}


		public class CreditListing
		{
			public int ID { get; set; }
			public string Person { get; set; }
			public string Credit { get; set; }
		}

		[return: JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public jqGridPacket<CreditListing> GetCastJson(int prodId, int which)
		{
			IQueryable<CreditListing> credits = null;
			var paging = new jqGridPager(this.Request.Params);
			switch (which)
			{
				case 0:     // Cast
					credits = (from r in db.Roles
							   where r.ProductionID == prodId
							   select new CreditListing
							   {
								   Person = r.People.FullName,
								   Credit = r.Role1,
								   ID = r.RoleID
							   });
/*
"SELECT [People].[FirstName] + ' ' +  [People].[LastName] as 'Person', [Roles].[Role], [Roles].[PK] FROM [People], [" +
"Roles] WHERE (([Roles].[ProductionID] = @ProductionID) AND ([Roles].[PersonID] =" +
" [People].[PersonID]))";
 */
					break;

				case 1:     // Crew
					credits = (from pc in db.ProductionCredits
							   where pc.ProductionID == prodId
							   orderby pc.CreditID
							   select new CreditListing
							  {
								  Person = pc.People.FullName,
								  Credit = pc.CreditName.Credit,
								  ID = pc.PK
							  });
//@"SELECT [People].[FirstName] + ' ' +  [People].[LastName] as 'Person', [CreditNames].[Credit], [ProductionCredits].[PK] 
// FROM [People], [CreditNames], [ProductionCredits] 
// WHERE (([ProductionCredits].[ProductionID] = @ProductionID) 
// AND ([ProductionCredits].[CreditID] = [CreditNames].[CreditID]) AND ([ProductionCredits].[PersonID] = [People].[PersonID])) 
// order by [CreditNames].[CreditID]";
					break;

				case 2:     //Author
					credits = (from pc in db.PlayCredits
							   join pr in db.Productions on pc.PlayID equals pr.PlayID
							   where pr.ProductionID == prodId
							   orderby pc.CreditID
							   select new CreditListing
							   {
								   Person = pc.People.FullName,
								   Credit = pc.CreditName.Credit + " by ",
								   ID = pc.PK
							   });

//@"SELECT  RTRIM(P.FirstName) + ' ' + RTRIM(P.LastName) AS [Person], CN.Credit + ' by ' AS Credit, PC.PK " +
//@"FROM    PlayCredit PC INNER JOIN " +
//@"CreditNames CN ON PC.CreditID = CN.CreditID INNER JOIN " +
//@"People P ON PC.PersonID = P.PersonID inner join Productions PR on pr.playid = PC.playid " +
//@"WHERE  (PR.PRoductionID = @ProductionID) " +
//@"ORDER BY PC.CreditID";
					break;

				default:
					return new jqGridPacket<CreditListing>();
			}

		/*
			jqGridPacket<CreditListing> packet = new jqGridPacket<CreditListing>();
			packet.total = credits.Length;
			packet.page = 0;
			packet.records = credits.Length;
			packet.rows = credits;
		 */
			/*
			var creditPage = paging.AddPaging(credits).ToList();

			var page = new jqGridPacket<CreditListing>(creditPage);
			//page.page = paging.Page;
			//page.records = credits.Count();
			//page.total = (page.records + paging.Rows - 1) / paging.Rows;
			paging.SetResponse(page, credits.Count());
			return page;
			 * */
			return paging.PackageResponse(credits);

		}
		public void GetRolesText(string term, int limit, int prodid)
		{
			if (limit == 0) limit = 10;
			//	select  DISTINCT Role  as DbComboText, 1 as DbComboValue FROM roles WHERE productionid 
			// IN (SELECT productionid FROM productions WHERE playid = @Playid)";
			var query = (from pr in db.Productions
						 join pr2 in db.Productions on pr.Play.PlayID equals pr2.Play.PlayID
						 join r in db.Roles on pr2.ProductionID equals r.ProductionID
						 where pr.ProductionID == prodid && term.CompareTo(r.Role1) <= 0
						 orderby r.Role1
						 select r.Role1).Distinct().ToList().Take(limit).ToList();

			this.CancelView();
			this.HttpContext.Response.ContentType = "text/text";
			query.ForEach(p => RenderText(p + Environment.NewLine));

		}

		[return: JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public Status DeleteJson(int id)
		{
			var prod = db.Productions.First(pr => pr.ProductionID == id);
			PropertyBag["Title"] = prod.Play.Title;
			PropertyBag["Troupe"] = prod.Troupe.Name;
			AdminController.RecordUserAction(db, this, "deleteprod", id, PropertyBag);
			db.DeleteProduction(id);
			return Status.OK;
		}


		[return: JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public ProductionListing EditDetails(int id, int troupeid, int venueid, int playid, DateTime start, DateTime end, string comments)
		{
			Production prod;
			string action;
			if (id == 0)
			{
				prod = new Production();
				db.Productions.InsertOnSubmit(prod);
				action = "added";
			}
			else
			{
				prod = db.Productions.FirstOrDefault(p => p.ProductionID == id);
				if (prod == null)
					return new ProductionListing() { ID = 0, Title = "(bad production id)" };
				action = "updated";
			}
			prod.TroupeID = troupeid;
			prod.VenueID = venueid;
			prod.PlayID = playid;
			prod.FirstPerformance = start;
			prod.LastPerformance = end;
			prod.Comments = comments;

			try
			{
				db.SubmitChanges();
			}
			catch (Exception ex)
			{
				return new ProductionListing() { ID = 0, Title = ex.Message };
			}

			PropertyBag["title"] = prod.Play.Title;
			PropertyBag["troupe"] = prod.Troupe.Name;
			PropertyBag["venue"] = prod.Venue.Name;
			PropertyBag["From"] = prod.FirstPerformance;
			PropertyBag["ToDate"] = prod.LastPerformance.Value;
			PropertyBag["action"] = action;

			AdminController.RecordUserAction(db, this, "EditProd", prod.ProductionID, PropertyBag);

			return new ProductionListing() { ID = prod.ProductionID, Title = prod.Play.Title };
		}


		public void ShowInfoJson(int ProductionId)
		{
			var query = (from pr in db.Productions
						 where pr.ProductionID == ProductionId
						 select new
						 {
							 PlayId = pr.PlayID,
							 Title = pr.Play.Title,
							 FirstPerformance = pr.FirstPerformance,
							 LastPerformance = pr.LastPerformance
						 }).FirstOrDefault();

			this.CancelView();
			this.HttpContext.Response.ContentType = "text/text";
			JSONHelper json = Helpers["JSON"] as JSONHelper;
			RenderText(json.ToJSON(query));

		}

		public class CreditLine
		{
			public int ID { get; set; }
			public string Credit { set; get; }
		}

		[return: JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public CreditLine[] GetCreditsJson(string term, int limit, int which)
		{
			var query = (from cr in db.CreditNames
						orderby cr.Credit
						where term.CompareTo(cr.Credit) <= 0
						select new CreditLine
						{
							Credit = cr.Credit + " by",
							ID = cr.CreditID
						});

			// type = 1 = Productions credits
			// type = 2 = Play credit.
			if (which == 1)
				query = query.Where(cr => cr.ID > 99);
			else
				query = query.Where(cr => cr.ID < 100);
// SELECT [CreditID], [Credit] + ' by ' as [Credit] FROM [CreditNames] WHERE ([CreditID] " + limit + ") order by 2";

			//this.CancelView();
			//this.HttpContext.Response.ContentType = "text/json";
			//JSONHelper json = Helpers["JSON"] as JSONHelper;
			//RenderText(json.ToJSON(query.Take(limit).ToArray()));

	
			return query.Take(limit).ToArray();
		}

		[return: JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public PerfTime[] GetPerfsJson(int ProductionId)
		{
			var query = from pf in db.Performances
						where pf.ProductionID == ProductionId
						select new PerfTime
						{
							EventID = pf.PK,
							Date = pf.date.Value.Date.ToString(),
							Title = pf.date.Value.ToShortTimeString(),
							URL ="#" //  pf.date.Value.ToShortDateString()
						};

			//this.CancelView();
			//this.HttpContext.Response.ContentType = "text/json";
			//JSONHelper json = Helpers["JSON"] as JSONHelper;
		
			//RenderText(Util.FixJsonDates(json.ToJSON(query.ToArray())));
			return query.ToArray();
		}

		public class PerfTime
		{
			public int EventID {get; set;}
			public string Date  {get; set;}
			public string Title  {get; set;}
			public string URL { get; set; }
		}


		[return: JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public PerfTime[] GetSchedulePerfsJson(int ProductionId, int SchedId)
		{
			var info = (from pr in db.Productions
						where pr.ProductionID == ProductionId
						select new
						{
							pr.TroupeID,
							FirstPerformance = pr.FirstPerformance
						}).First();


			var query = from pf in db.StandardSchedDetails
						where pf.SchedID == SchedId
					let TheDate = info.FirstPerformance.AddDays(pf.dateoffset.Value).AddHours(pf.hours.Value).AddMinutes(pf.minutes.Value)
						select new PerfTime
					{
						EventID = 0,
						Date = TheDate.Date.ToString(),
						Title = TheDate.ToShortTimeString(),
						URL = "#"
					};

			return query.ToArray();
		}

		[return: JSONReturnBinder]
		[Rescue(typeof(JsonRescueController))]
		public Status SavePerfsJson(int ProductionId, [JSONBinder] PerfTime[] Dates)
		{
			var prod = db.Productions.FirstOrDefault(pr => pr.ProductionID == ProductionId);
			if (prod == null)
				return Status.BAD;

			prod.HasPerfs = Dates.Length > 0;

			db.Performances.DeleteAllOnSubmit(db.Performances.Where(pf=> pf.ProductionID == ProductionId));
			db.Performances.InsertAllOnSubmit(Dates.Select(pt=> 
				new Performance 
				{ 
					ProductionID = ProductionId,
					date = DateTime.Parse(pt.Date).Date + DateTime.Parse(pt.Title).TimeOfDay
				}));
			db.SubmitChanges();

			return Status.OK;
		}

		/// <summary>
		/// RSSs this instance.
		///   
		/// </summary>
		public void Rss()
		{
			CancelView();
			Response.ContentType = "application/rss";
			var when = DateTime.Now;

			var q = from prod in db.Productions
					where prod.FirstPerformance < when.AddDays(8)
					&& prod.LastPerformance > when.AddDays(-1)
					&& prod.FlowerID == null
					orderby prod.Play.SortTitle
					select new 
					{
						Title = prod.Play.Title,
						PlayId = prod.PlayID,
						Description = prod.Play.Comments,
						ProductionId = prod.ProductionID,
						Troupe = prod.Troupe.Name,
						Venue = prod.Venue.Name,
						City = prod.Venue.City,
						Lng = prod.Venue.lng,
						Lat = prod.Venue.lat,
						FirstPerformance = prod.FirstPerformance,
						LastPerformance = prod.LastPerformance.Value,
					};
			var md = new Markdown();
			Uri uri = Request.Uri;
			RssFeed feed  = new RssFeed(uri, "NJTheater.com - Productions Channel");
			feed.Channel.Description = "List of theatrical productions on all levels in New Jersey for week of {0:M/d/yyyy}".With(when);
			feed.Channel.ManagingEditor = ConfigurationManager.AppSettings["SysadminEmail"];
			feed.Channel.Webmaster = ConfigurationManager.AppSettings["SysadminEmail"];
			feed.Channel.Language = CultureInfo.CurrentCulture;

			feed.Channel.Image = new RssImage();
			feed.Channel.Image.Title = "NJTheater.com";
			var photo = new UriBuilder(uri);
			photo.Path = "content/images/NJTheaterMask.gif";
			feed.Channel.Image.Url = photo.Uri;
			feed.Channel.Image.Link = uri;
			feed.Channel.Image.Width = 141;
			feed.Channel.Image.Height = 145;

			foreach (var prod in q)
			{
				RssItem item = new RssItem();
				item.Title = prod.Title;
				var link = new UriBuilder(uri);
				link.Path =this.Context.ApplicationPath + "/Show/{0}/Display.rails".With(prod.ProductionId);
				item.Link = link.Uri;
				item.Description = // HttpContext.Server.HtmlEncode
					(@"<![CDATA[{0}< br/>({1:M/dd/yyyy} - {2:M/d/yyyy}<br />{3}<br />at {4} ({5})<br/>{6}]]>"
					.With(prod.Title, prod.FirstPerformance, prod.LastPerformance, prod.Troupe,
					prod.Venue,  prod.City, md.Transform(prod.Description)));
				var ev = new EventSyndicationExtension();
				ev.Context.Location = "{0}, {1}".With(prod.Venue, prod.City);
				ev.Context.Organizer = prod.Troupe;
				ev.Context.Type = "production";
				ev.Context.StartDate = prod.FirstPerformance;
				ev.Context.EndDate = prod.LastPerformance;
				item.AddExtension(ev);
				if (prod.Lat.HasValue && prod.Lng.HasValue)
				{
					var geo = new BasicGeocodingSyndicationExtension();
					geo.Context.Latitude = Convert.ToDecimal(prod.Lat.Value);
					geo.Context.Longitude= Convert.ToDecimal(prod.Lng.Value);
					item.AddExtension(geo);
				}
				item.PublicationDate = DateTime.Now;
				feed.Channel.AddItem(item);
			}

			feed.Save(Response.OutputStream);
		}
	}  
}
